﻿#pragma once

/// 主要就是处理事件

#include <QWidget>
#include <QFont>

#include "svgshape.h"
#include "svgcanvas.h"
#include "svgpalette.h"

class QSvgRenderer;
class QLineEdit;
class QMenu;
class QAction;

constexpr QPointF INVALID_POINT_F(NAN, NAN);

enum class SvgOperationType
{
	AddLine,
	AddRect,
	AddEllipse,
	// 等腰三角形
	AddIsoscelesTriangle,
	// 五边形
	AddPentagon,
	// 六边形
	AddHexagon,
	AddFreeLine,
	AddText,
	SelectShape,

	// # 特殊操作, 以下模式并没有按钮
	// ## 暂时模式
	// 移动图形, SelectShape 模式下，已选中图形，再次点击选中的图形，进入该模式，松开鼠标退出
	MoveShape,
	// 拖拽图形，改变大小, SelectShape 模式下, 已选中单个图形，鼠标放在选中图形显示的框的小蓝方格上，会看到鼠标样式变化，就代表进入了该模式，鼠标移开退出，不需要点击
	// 注意，进入了，保持点击是不会退出的，松开的时候才会退出
	ChangeShapeSize,
};

class SvgWidget: public QWidget
{
	Q_OBJECT

private:
	enum class _RectEndPoint
	{
		Left,
		Right,
		Top,
		Bottom,
		LeftBottom,
		RightTop,
		LeftTop,
		RightBottom,
		None, // special, 表示没有选中端点
	};

public:
	explicit SvgWidget(QWidget* parent);

	void Init();

public slots:
	void ChangeOperation(SvgOperationType operation);
	void SaveSvg(const QString& path);
	void OpenSvg(const QString& fileName);
	void NewSvg();

	void ChangeCanvasSize(double width, double height);
	void ChangeCanvasBackground(const QColor& color);

	void ChangeSelectedStrokeWidth(double width);

	void ChangeSelectedLinePos(const QLineF& line);

	void ChangeScale(double scale);

	void ChangeColor(const QColor& color, SvgColorTarget target);

	void ViewPortChanged();

signals:
	void CanvasSelected(const SvgCanvas& canvas);
	void SelectedShapesUpdated(vector<SvgShape*>& shape);
	void ColorChanged(const QColor& inner, const QColor& line);
	void ScaleChanged(double scale);
	void OperationChanged(SvgOperationType op);

protected:
	void paintEvent(QPaintEvent* event) override;

	void contextMenuEvent(QContextMenuEvent* event) override;
	void mousePressEvent(QMouseEvent* event) override;
	void mouseReleaseEvent(QMouseEvent* event) override;
	void mouseMoveEvent(QMouseEvent* event) override;
	void showEvent(QShowEvent* event) override;
	void resizeEvent(QResizeEvent* event) override;
	void wheelEvent(QWheelEvent* event) override;
	void keyPressEvent(QKeyEvent* event) override;
	void mouseDoubleClickEvent(QMouseEvent* event) override;

private:
	void _InitUi();

	// 计算画布放在中心情况的 原点, 如果画布比窗口大，那就是 (0, 0)
	QPoint _CalCenterBasePoint() const;

	// 考虑缩放的 画布 宽高
	double _CanvasWidth() const;
	double _CanvasHeight() const;

	void _PainterToCanvasPos(QPainter& painter) const;
	void _PaintBackground(QPainter& painter) const;
	void _PaintSelectedShapeEffect(QPainter& painter) const;
	void _PaintPreview(QPainter& painter) const;
	void _PaintFreeLinePoints(QPainter& painter) const;

	// 只支持 矩形，椭圆，直线, 五边形, 等腰三角形, 会设置 Color
	unique_ptr<SvgShape> _CreateShape(SvgOperationType type, const QPointF& p0, const QPointF& p1) const;

	// 这个是只有一个图形被选中的情况
	void _NewShapeSelected(SvgShape* shape);

	unique_ptr<SvgRect> _GetSelectRect(const QPointF& pos) const;

	bool _OpenWpsSvg(const QString& fileName);
	bool _OpenGeneralSvg(const QString& fileName);
	void _PaintGeneralSvg(QPaintEvent* event);
	bool _CheckSupport();

	QRectF _GetNewBoundingRect(const QPointF& d);

	void _AddShapeToCanvas(unique_ptr<SvgShape> shape);

	void _RePaint();
	void _RePaint(const QRectF& rect);

	void _ShowTextEdit(QPoint pos) const;
	void _SetTextEdit(QPoint pos) const;
	void _CreateTextShape(const QPointF& pos); 

private slots:
	void _LineEditInput(const QString& text);
	void _DeleteSelectedShape();
	void _BringSelectedShapeToFront();
	void _SendSelectedShapeToBack();
	void _CopyShapes();
	void _PasteShapes();
	// 如果 textEdit 是显示的，且当前有文字, 则添加 SvgText, 并隐藏 textEdit
	void _HandleTextEdit();

private:
	// 点是否在当前矩形的端点上，上下左右中心点也认为是端点
	static _RectEndPoint _PointInRectEndPoint(const QPointF& point, const QRectF& rect);
	// d 是移动的轨迹，就是 m_mouseLastPos - mouseCurPos, mode 是按住的端点， rawRect 是原来的 boundingRect
	// todo: 函数名待修改

private:
	// 当前操作
	SvgOperationType m_operation = SvgOperationType::SelectShape;
	QColor m_lineColor = QColor(0, 0, 0);
	QColor m_innerColor = QColor(0xff, 0xff, 0xff, 0);

	// # 右键菜单相关
	QMenu* m_contextMenu = nullptr;
	QAction* m_deleteShapeAct = nullptr;
	QAction* m_shapeToTopAct = nullptr;
	QAction* m_shapeToBackAct = nullptr;
	QAction* m_copyAct = nullptr;
	QAction* m_pasteAct = nullptr;

	// # 画布相关
	SvgCanvas m_canvas;
	double m_scale = 1;
	// 这两个坐标都是相对于画布
	QPointF m_pressedPos = INVALID_POINT_F;
	QPointF m_mouseLastPos = INVALID_POINT_F;

	// # 选中相关
	// 选中的图形
	vector<SvgShape*> m_selectedShapes;
	// 选框的矩形。。。
	unique_ptr<SvgRect> m_selectRect;

	// 添加图形的预览, 只处理通过矩形框添加的, 目前是改变了直接重新new一个，但实际上没有必要。。。
	unique_ptr<SvgShape> m_previewShape;

	// copy, 如果只是保存 SvgShape* 的话，可能原图形被删除了，同时原图形被修改了，之后的怎么处理也是一个问题
	SvgShapeVec m_copiedShapes;

	// # 添加文字相关
	// 添加文字用的 lineEdit，有点偷懒了，但是自己弄 inputMethod 有点麻烦
	QLineEdit* m_textEdit = nullptr;
	// 因为 text 处理过程比较特殊，就单独弄一个了
	SvgText* m_editingText = nullptr;
	QFont m_font;

	// 自由线绘制过程中的点集，释放鼠标的时候会转换成 贝塞尔 曲线添加到 canvas
	std::vector<QPointF> m_freeLinePoints;

	// # 拖拽相关, 只有在拖拽模式的时候有用
	_RectEndPoint m_shapeEndPoint = _RectEndPoint::None;

	// 对于通用 svg 的特殊处理, 其实放这里很不合理，但是因为要求不高，简单处理吧。。。
	bool m_isGeneralSvg = false;
	QSvgRenderer* m_svgGeneralRender = nullptr;
};
